from itertools import cycle
import numpy as np
from sklearn.cluster import DBSCAN
from sklearn import metrics
import matplotlib.pyplot as plt
# 加载数据
input_file = "F:/python学习资料/Python-Machine-Learning-Cookbook-master/Chapter04/data_perf.txt"
x = []
with open(input_file,'r') as f:
    for line in f.readlines():
        data = [float(i) for i in line.split(",")]
        x.append(data)

X = np.array(x)
# 找到最假的epsilon配置
eps_grid = np.linspace(0.3,1.2,num=10)
silhouette_scores = []
eps_best = eps_grid[0]
silhouette_score_max = -1
model_best = None
labels_best = None
# 扫描参数空间
for eps in eps_grid:
    # 训练DBSCAN模型
    model = DBSCAN(eps=eps,min_samples=5).fit(X)
    # 提取标签
    labels = model.labels_
    # 提取性能指标
    silhouette_score = round(metrics.silhouette_score(X,labels),4)
    silhouette_scores.append(silhouette_score)
    print("Epsilon",eps,'--> silhouette score:',silhouette_score)
    if silhouette_score > silhouette_score_max:
        silhouette_score_max = silhouette_score
        eps_best = eps
        model_best = model
        labels_best = labels

# 画出不同半径设置下的轮廓系数分
plt.figure()
plt.bar(eps_grid,silhouette_scores,width=0.05,color='k',align='center')
eps = eps_best
# print(eps)
title = 'Silhouette score='+str(round(eps_best,2))
plt.title(title)
plt.show()
# 保留最佳模型和标签
model = model_best
labels = labels_best
# 检查标签中没有被分配过的标签点
offset = 0
if -1 in labels:
    offset = 1
# 数据中簇的个数
num_clusters = len(set(labels)) - offset
print("已确定的簇的个数=",num_clusters)
# 从训练的模型中提取核心样本
mask_core = np.zeros(labels.shape,dtype=bool)
# core_sample_indices_ 核心样本点
mask_core[model.core_sample_indices_] = True
plt.figure()
labels_unique = set(labels)
markers = cycle('vo^s<>')
for cur_label,marker in zip(labels_unique,markers):
    # 用黑点表示未分配的数据点
    if cur_label == -1:
        marker ='.'
    # 为当前标签添加标记的样式
    cur_mask = (labels == cur_label)
    cur_data = X[cur_mask & mask_core]
    plt.scatter(cur_data[:,0],cur_data[:,1],marker=marker,edgecolors='black',s=96,facecolors='none')
    cur_data = X[cur_mask & ~mask_core]
    plt.scatter(cur_data[:,0],cur_data[:,1],marker=marker,edgecolors='black',s=32)
plt.title("Data separated into clusters")
plt.show()